From af0ffa86fad43a78329e334a105d766b1b0acbb4 Mon Sep 17 00:00:00 2001 From: "iap10@nidd.cl.cam.ac.uk" Date: Sat, 20 Dec 2003 23:39:05 +0000 Subject: [PATCH] bitkeeper revision 1.652.2.1 (3fe4dd99t24zD9Wu1VbWDg5fOnRCgQ) Cleanup and documentation improvement to createlinuxdom.py/XenoUtil.py along with addition of VM auto restart facility (latter curtesy of Mark Williamson). --- .rootkeys | 1 - BitKeeper/etc/logging_ok | 1 + tools/examples/createlinuxdom.py | 214 ++++++++++++++++++++----------- tools/examples/mynewdom.py | 114 ---------------- tools/xc/lib/Makefile | 4 +- tools/xc/py/XenoUtil.py | 21 ++- 6 files changed, 155 insertions(+), 200 deletions(-) delete mode 100755 tools/examples/mynewdom.py diff --git a/.rootkeys b/.rootkeys index 8506a8fff8..bbc5d2ac78 100644 --- a/.rootkeys +++ b/.rootkeys @@ -42,7 +42,6 @@ 3fbe2f12OPAkzIUtumU3wRAihnhocQ tools/examples/createlinuxdom.py 3fbe2f12dZbmXLlgQdMgkmnSUj23AQ tools/examples/destroydom.py 3fbe2f12ltvweb13kBSsxqzZDAq4sg tools/examples/listdoms.py -3fca7788tBihusQSq3HJI-YKQTN2iQ tools/examples/mynewdom.py 3fca7700PVj36cZObaFZlQicRiw1pQ tools/examples/pincpu.py 3fd8bc48ww3aOqPhYjCr8KGulG0NQQ tools/examples/readxenconsolering.py 3fccbe068ov0YCxnk-2m4law19QMmA tools/examples/startdom.py diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 461b17a97a..da1235fdb0 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -10,6 +10,7 @@ br260@labyrinth.cl.cam.ac.uk br260@laudney.cl.cam.ac.uk iap10@freefall.cl.cam.ac.uk iap10@labyrinth.cl.cam.ac.uk +iap10@nidd.cl.cam.ac.uk iap10@striker.cl.cam.ac.uk jws22@gauntlet.cl.cam.ac.uk jws@cairnwell.research diff --git a/tools/examples/createlinuxdom.py b/tools/examples/createlinuxdom.py index d01a2ea0b7..e183b422f8 100755 --- a/tools/examples/createlinuxdom.py +++ b/tools/examples/createlinuxdom.py @@ -2,107 +2,169 @@ # # Example script for creating and building a new Linux guest OS for Xen. +# It takes an optional parameter that specifies offsets to be added to the +# ip address and root partition numbers, enabling multiple domains to be +# started from the one script. +# +# Edit as required... # -import Xc, XenoUtil, sys, os +import Xc, XenoUtil, string, sys, os, time, socket -# Variable declaration. Set these up properly later on, as needed. -nfsserv = nfspath = root_partn = usr_partn = "" +# initialize a few variables that might come in handy +thishostname = socket.gethostname() +guestid = 0 +if sys.argv >= 2: + guestid = string.atoi(sys.argv[1]) + print "Offset to add to guest's IP etc : %d\n" % guestid + +##### This section of the code establishes various settings to be used +##### for this guest virtual machine -# STEP 1. Specify kernel image file. -image = "FULL_PATH_TO_IMAGE" +# STEP 1. Specify kernel image file. Can be gzip'ed. +image = "../../../install/boot/xenolinux.gz" # STEP 2. How many megabytes of memory for the new domain? memory_megabytes = 64 # STEP 3. A handy name for your new domain. -domain_name = "My new domain" +domain_name = "This is VM %d" % guestid + +# STEP 4. Specify IP address(es), netmask and gateway for the new +# domain. You need to configure IP addrs within the domain just as +# you do normally. This is just to let Xen know about them so it can +# route packets appropriately. -# STEP 4. Specify IP address, netmask and gateway for the new domain. -ipaddr = "ADDRESS" +#ipaddr = ["111.222.333.444","222.333.444.555"] +ipaddr = [XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),guestid)] netmask = XenoUtil.get_current_ipmask() gateway = XenoUtil.get_current_ipgw() +nfsserv = '169.254.1.0' # You need to set this if you're using NFS root -# STEP 5a. Specify NFS server and path to rootfs (only needed for network boot) -nfsserv = "ADDRESS" -nfspath = "FULL_PATH_TO_ROOT_DIR" - -# STEP 5b. Specify root partition on local disc (if not NFS booting) -#root_partn = "/dev/sda2" -# (NB. The following is only needed for a separate shared read-only /usr) -# (usr_partn = "/dev/sda6") - -# STEP 6. Check that the following cmdline setup is to your taste. -cmdline = "ip="+ipaddr+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off" -if root_partn: - # Boot from local disc. May specify a separate /usr. - cmdline = cmdline + " root="+root_partn+" ro" - if usr_partn: - " usr="+usr_partn -elif nfsserv: - # NFS boot - cmdline = cmdline + " root=/dev/nfs" - cmdline = cmdline + " nfsroot="+nfspath - -if root_partn: - root_info = XenoUtil.lookup_blkdev_partn_info(root_partn) - if not root_info: - print "Could not obtain info on partition '" + root_partn + "'" - sys.exit() +# STEP 5. Identify any physcial partitions or virtual disks you want the +# domain to have access to, and what you want them accessible as +# e.g. vbds = [ ('phy:sda1','sda1', 'w'), +# ('phy:sda4','sda%d' % (3+guestid), 'r'), +# ('vd:as73gd784dh','hda1','w') ] -if usr_partn: - usr_info = XenoUtil.lookup_blkdev_partn_info(usr_partn) - if not usr_info: - print "Could not obtain info on partition '" + usr_partn + "'" - sys.exit() +vbds = [ ('phy:sda%d'%(7+guestid),'sda1','w' ), + ('phy:sda6','sda6','r'), + ('phy:cdrom','hdd','r') ] -if not os.path.isfile( image ): - print "Image file '" + image + "' does not exist" - sys.exit() +# STEP 6. Build the command line for the new domain. Edit as req'd. +# You only need the ip= line if you're NFS booting or the root file system +# doesn't set it later e.g. in ifcfg-eth0 or via DHCP +# You can use 'extrabit' to set the runlevel and custom environment +# variables used by custom rc scripts (e.g. DOMID=, usr= ) -xc = Xc.new() +ipbit = "ip="+ipaddr[0]+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off" +rootbit = "root=/dev/sda1 ro" +#rootbit = "root=/dev/nfs nfsroot=/full/path/to/root/directory" +extrabit = "4 DOMID=%d usr=/dev/sda6" % guestid +cmdline = ipbit +" "+ rootbit +" "+ extrabit -id = xc.domain_create( mem_kb=memory_megabytes*1024, name=domain_name ) -if id <= 0: - print "Error creating domain" - sys.exit() +# STEP 7. Set according to whether you want the script to watch the domain +# and auto-restart it should it die or exit. -if xc.linux_build( dom=id, image=image, cmdline=cmdline ): - print "Error building Linux guest OS" - xc.domain_destroy ( dom=id ) - sys.exit() +auto_restart = False +#auto_restart = True -if root_partn: - if xc.vbd_create( dom=id, vbd=root_info[0], writeable=1 ): - print "Error creating root VBD" - xc.domain_destroy ( dom=id ) + +##### Print some debug info just incase things don't work out... +##### + +print "Domain image : ", image +print "Domain memory : ", memory_megabytes +print "Domain IP address(es) : ", ipaddr +print "Domain block devices : ", vbds +print 'Domain cmdline : "%s"' % cmdline + + +##### Code beyond this point is actually used to manage the mechanics of +##### starting (and watching if necessary) guest virtual machines. + +# Obtain an instance of the Xen control interface +xc = Xc.new() + +# This function creates, builds and starts a domain, using the values +# in the global variables, set above. It is used in the subsequent +# code for starting the new domain and rebooting it if appropriate. +def make_domain(): + """Create, build and start a domain. + Returns: [int] the ID of the new domain. + """ + + # set up access to the global variables declared above + global image, memory_megabytes, domain_name, ipaddr, netmask + global vbds, cmdline, xc + + if not os.path.isfile( image ): + print "Image file '" + image + "' does not exist" sys.exit() - if xc.vbd_grow( dom=id, - vbd=root_info[0], - device=root_info[1], - start_sector=root_info[2], - nr_sectors=root_info[3] ): - print "Error populating root VBD" - xc.domain_destroy ( dom=id ) + + id = xc.domain_create( mem_kb=memory_megabytes*1024, name=domain_name ) + print "Created new domain with id = " + str(id) + if id <= 0: + print "Error creating domain" sys.exit() -if usr_partn: - if xc.vbd_create( dom=id, vbd=usr_info[0], writeable=0 ): - print "Error creating usr VBD" + ret = xc.linux_build( dom=id, image=image, cmdline=cmdline ) + if ret < 0: + print "Error building Linux guest OS: " + print "Return code from linux_build = " + str(ret) xc.domain_destroy ( dom=id ) sys.exit() - if xc.vbd_grow( dom=id, - vbd=usr_info[0], - device=usr_info[1], - start_sector=usr_info[2], - nr_sectors=usr_info[3] ): - print "Error populating usr VBD" + + # setup the virtual block devices + for ( uname, virt_name, rw ) in vbds: + virt_dev = XenoUtil.blkdev_name_to_number( virt_name ) + + segments = XenoUtil.lookup_disk_uname( uname ) + if not segments: + print "Error looking up %s\n" % uname + xc.domain_destroy ( dom=id ) + sys.exit() + + if xc.vbd_create( dom=id, vbd=virt_dev, writeable= rw=='w' ): + print "Error creating VBD vbd=%d writeable=%d\n" % (virt_dev,rw) + xc.domain_destroy ( dom=id ) + sys.exit() + + for (s_dev,s_start,s_len,s_type) in segments: + if xc.vbd_grow( dom=id, + vbd=virt_dev, + device=s_dev, + start_sector=s_start, + nr_sectors=s_len ): + print "Error populating VBD vbd=%d\n" % virt_dev + xc.domain_destroy ( dom=id ) + sys.exit() + + # setup virtual firewall rules for all aliases + for ip in ipaddr: + XenoUtil.setup_vfr_rules_for_vif( id, 0, ip ) + + if xc.domain_start( dom=id ) < 0: + print "Error starting domain" xc.domain_destroy ( dom=id ) sys.exit() -XenoUtil.setup_vfr_rules_for_vif( id, 0, ipaddr ) + return id +# end of make_domain() + + + +# The starting / monitoring of the domain actually happens here... + +# start the domain and record its ID number +current_id = make_domain() + +# if the auto_restart flag is set then keep polling to see if the domain is +# alive - restart if it is not by calling make_domain() again (it's necessary +# to update the id variable, since the new domain may have a new ID) -if xc.domain_start( dom=id ): - print "Error starting domain" - xc.domain_destroy ( dom=id ) - sys.exit() +while auto_restart: + time.sleep(1) + if not xc.domain_getinfo(current_id): + print "The virtual machine has terminated, restarting in a new domain" + current_id = make_domain() diff --git a/tools/examples/mynewdom.py b/tools/examples/mynewdom.py deleted file mode 100755 index 29c8a35419..0000000000 --- a/tools/examples/mynewdom.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python - -# Example script for creating and building a new Linux guest OS for -# Xen. THIS IS VERY SITE SPECIFIC, but shows an example configuration -# using multiple root partitions with a common /usr. e.g. Domain1 -# uses root /dev/sda8, usr /dev/sda6, and the next sequential IP address. - -import Xc, XenoUtil, sys, os, socket, re - -# Variable declaration. Set these up properly later on, as needed. -nfsserv = nfspath = root_partn = usr_partn = "" -shost = re.search( '([a-zA-Z]+)[-.]', socket.gethostname() ).group(1) - -# STEP 1. Specify kernel image file. -image = "/usr/groups/srgboot/%s/xenolinux.gz" % shost - -# STEP 2. How many megabytes of memory for the new domain? -memory_megabytes = 64 - -# STEP 3. A handy name for your new domain. -domain_name = "My new domain" - -# Allocate new domain ad get its domain id -xc = Xc.new() -id = xc.domain_create( mem_kb=memory_megabytes*1024, name=domain_name ) -if id <= 0: - print "Error creating domain" - sys.exit() - -# Set the CPU, or leave to round robin allocation -#xc.domain_pincpu( dom=id, cpu=1 ) - -# STEP 4. Specify IP address, netmask and gateway for the new domain. -ipaddr = XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),id) -netmask = XenoUtil.get_current_ipmask() -gateway = XenoUtil.get_current_ipgw() - -# STEP 5a. Specify NFS server and path to rootfs (only needed for network boot) -#nfsserv = "ADDRESS" -#nfspath = "FULL_PATH_TO_ROOT_DIR" - -# STEP 5b. Specify root partition on local disc (if not NFS booting) -root_partn = "/dev/sda%d" % (7+id) -# (NB. The following is only needed for a separate shared read-only /usr) -usr_partn = "/dev/sda6" - -# STEP 6. Check that the following cmdline setup is to your taste. -cmdline = "ip="+ipaddr+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off" -if root_partn: - # Boot from local disc. May specify a separate /usr. - cmdline = cmdline + " root="+root_partn+" ro" - if usr_partn: - " usr="+usr_partn -elif nfsserv: - # NFS boot - cmdline = cmdline + " root=/dev/nfs" - cmdline = cmdline + " nfsroot="+nfspath - -if root_partn: - root_info = XenoUtil.lookup_blkdev_partn_info(root_partn) - if not root_info: - print "Could not obtain info on partition '" + root_partn + "'" - sys.exit() - -if usr_partn: - usr_info = XenoUtil.lookup_blkdev_partn_info(usr_partn) - if not usr_info: - print "Could not obtain info on partition '" + usr_partn + "'" - sys.exit() - -if not os.path.isfile( image ): - print "Image file '" + image + "' does not exist" - sys.exit() - - -if xc.linux_build( dom=id, image=image, cmdline=cmdline ): - print "Error building Linux guest OS" - xc.domain_destroy ( dom=id ) - sys.exit() - -if root_partn: - if xc.vbd_create( dom=id, vbd=root_info[0], writeable=1 ): - print "Error creating root VBD" - xc.domain_destroy ( dom=id ) - sys.exit() - if xc.vbd_grow( dom=id, - vbd=root_info[0], - device=root_info[1], - start_sector=root_info[2], - nr_sectors=root_info[3] ): - print "Error populating root VBD" - xc.domain_destroy ( dom=id ) - sys.exit() - -if usr_partn: - if xc.vbd_create( dom=id, vbd=usr_info[0], writeable=0 ): - print "Error creating usr VBD" - xc.domain_destroy ( dom=id ) - sys.exit() - if xc.vbd_grow( dom=id, - vbd=usr_info[0], - device=usr_info[1], - start_sector=usr_info[2], - nr_sectors=usr_info[3] ): - print "Error populating usr VBD" - xc.domain_destroy ( dom=id ) - sys.exit() - -XenoUtil.setup_vfr_rules_for_vif( id, 0, ipaddr ) - -if xc.domain_start( dom=id ): - print "Error starting domain" - xc.domain_destroy ( dom=id ) - sys.exit() diff --git a/tools/xc/lib/Makefile b/tools/xc/lib/Makefile index c19643e8fb..2693372048 100644 --- a/tools/xc/lib/Makefile +++ b/tools/xc/lib/Makefile @@ -22,7 +22,7 @@ install: all mkdir -p /usr/lib mkdir -p /usr/include cp -a $(LIB) /usr/lib - chmod 755 /usr/bin/$(LIB) + chmod 755 /usr/lib/$(LIB) cp -a xc.h /usr/include chmod 644 /usr/include/xc.h @@ -30,7 +30,7 @@ dist: all mkdir -p ../../../../install/lib mkdir -p ../../../../install/include cp -a $(LIB) ../../../../install/lib - chmod 755 ../../../../install/bin/$(LIB) + chmod 755 ../../../../install/lib/$(LIB) cp -a xc.h ../../../../install/include chmod 644 ../../../../install/include/xc.h diff --git a/tools/xc/py/XenoUtil.py b/tools/xc/py/XenoUtil.py index 850dd8ddb4..81fca35e47 100644 --- a/tools/xc/py/XenoUtil.py +++ b/tools/xc/py/XenoUtil.py @@ -12,7 +12,7 @@ def blkdev_name_to_number(name): # lookup_blkdev_partn_info( '/dev/sda3' ) -def lookup_blkdev_partn_info(partition): +def lookup_raw_partn(partition): """Take the given block-device name (e.g., '/dev/sda1', 'hda') and return a information tuple ( partn-dev, disc-dev, start-sect, nr-sects, type ) @@ -32,11 +32,10 @@ def lookup_blkdev_partn_info(partition): fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) line = fd.readline() if line: - return ( blkdev_name_to_number(drive), - blkdev_name_to_number(drive), + return [( blkdev_name_to_number(drive), 0, string.atol(line) * 2, - 'Disk' ) + 'Disk' )] return None # determine position on disk @@ -48,13 +47,21 @@ def lookup_blkdev_partn_info(partition): m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' + 'size=\s*([0-9]+), Id=\s*(\S+).*$', line) if m: - return ( blkdev_name_to_number(partition), - blkdev_name_to_number(drive), + return [( blkdev_name_to_number(drive), string.atol(m.group(1)), string.atol(m.group(2)), - m.group(3) ) + m.group(3) )] return None +def lookup_disk_uname( uname ): + ( type, d_name ) = string.split( uname, ':' ) + + if type == "phy": + segments = lookup_raw_partn( d_name ) + elif type == "vd": + segments = lookup_vd( d_name ) + + return segments def get_current_ipaddr(dev='eth0'): """Return a string containing the primary IP address for the given -- 2.30.2